/*************************************************************************************
*Copyright (c) 2011, Intel Mobile Communications GmbH. 
*All rights reserved.
*
*Redistribution and use in source and binary forms, with or without
*modification, are permitted provided that the following conditions are met:
*    * Redistributions of source code must retain the above copyright
*      notice, this list of conditions and the following disclaimer.
*    * Redistributions in binary form must reproduce the above copyright
*      notice, this list of conditions and the following disclaimer in the
*      documentation and/or other materials provided with the distribution.
*    * Neither the name of the <organization> nor the
*      names of its contributors may be used to endorse or promote products
*      derived from this software without specific prior written permission.
*
*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
*ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
*WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*DISCLAIMED. IN NO EVENT SHALL INTEL MOBILE COMMUNICATIONS GMBH. BE LIABLE FOR ANY
*DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
*(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
*ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
*SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************************/



#include "cef_block.h"
using namespace std;
//CEF Connection
cef_connection::cef_connection()
{
	id=0;
	type=0;
	name="default";
}
cef_connection::cef_connection(unsigned i,string n,unsigned t):id(i),name(n),type(t)
{
}
cef_connection::~cef_connection()
{
}
//Setters
void cef_connection::setName(string n)
{
	name=n;
}
void cef_connection::setID(unsigned i)
{
	id=i;
}
void cef_connection::setType(unsigned t)
{
	type=t;
}
//Getters
string cef_connection::getName()
{
	return name;
}
unsigned cef_connection::getID()
{
	return id;
}
unsigned cef_connection::getType()
{
	return type;
}
#ifdef _DEBUG	
void cef_connection::print()	
{
	cout<<"CEF Connection\nBEGIN\nShare Edge With\n";
	cout<<"Name: "<<name<<" ID: "<<id<<" Type: "<<type<<endl; 
	cout<<"END\n";
}
#endif
//CEF PORT
cef_port::cef_port()
{
	protocol="AXI";
	protocol_variant="NOBURST";
	max_outstanding_transactions=1;	
	address_width=0;
	read_data_width=0;
	write_data_width=0;
	position=NULL;
	domain_id=NULL;
	id=0;
	flit_width=1;

}
cef_port::cef_port(unsigned i,string p,string v,unsigned mot, unsigned aw,unsigned rw,unsigned ww, unsigned fw, pair<double,double>* o, unsigned did)
{
	id=i;
	protocol=p;
	protocol_variant=v;
	max_outstanding_transactions=mot;
	address_width=aw;
	read_data_width=rw;
	write_data_width=ww;
	position=o;
	flit_width=fw;
	domain_id=did;
}
cef_port::~cef_port()
{
}
//Setters
void cef_port::setID(unsigned i)
{
	id=i;
}
void cef_port::setMOT(unsigned mot)
{
	max_outstanding_transactions=mot;
	
}
void cef_port::setAddressWidth(unsigned aw)
{
	address_width=aw;
}
void cef_port::setReadDataWidth(unsigned rw)
{
	read_data_width;
}
void cef_port::setWriteDataWidth(unsigned ww)
{
	write_data_width;
}
void cef_port::setFlitWidth(unsigned fw)
{
	flit_width=fw;
}
void cef_port::setPosition(pair<double,double>* o)
{
	position=o;	
}
void cef_port::setDomainID(unsigned d)
{
	domain_id=d;
}
void cef_port::setProtocol(string p)
{
	protocol=p;
}
void cef_port::setProtocolVar(string pv)
{
	protocol_variant=pv;
}
//Getters
unsigned cef_port::getID()
{
	return id;
}
unsigned cef_port::getMOT()
{
	return max_outstanding_transactions;
}
unsigned cef_port::getAddressWidth()
{
	return address_width;
}

unsigned cef_port::getReadDataWidth()
{
	return read_data_width;
}
unsigned cef_port::getWriteDataWidth()
{
	return write_data_width;
}
unsigned cef_port::getFlitWidth()
{
	return flit_width;
}
pair<double,double>* cef_port::getPosition()
{
	return position;
}
unsigned cef_port::getDomainID()
{
	return domain_id;
}
string cef_port::getProtocol()
{
	return protocol;
}
string cef_port::getProtocolVar()
{
	return protocol_variant;
}
#ifdef _DEBUG	
void cef_port::print()	
{
	cout<<"CEF Port\nBEGIN\n";	
	cout <<"ID: "<< id;
	cout<<" Protocol: "<<protocol<<" Protocol Variant: "<<protocol_variant<<" MOT: "<<max_outstanding_transactions<<" Address Width: "<<address_width<<" ReadData Width: "<<read_data_width<<" WriteData Width: "<<write_data_width<<" DomainID: "<<domain_id<<" Position: "<<position->first<<","<<position->second<<endl;
	cout<<"END\n";
}
#endif
cef_block_blc_pos::cef_block_blc_pos()
{
	x=0;
	y=0;
	initialx=0;
	initialy=0;
}
cef_block_blc_pos::cef_block_blc_pos(double _x,double _y,double ix,double iy,bool m)
{
	x=_x;
	y=_y;
	initialx=ix;
	initialy=iy;
	movable=m;
		
}
cef_block_blc_pos::~cef_block_blc_pos()
{
}

//Setters
void cef_block_blc_pos::setX(double _x)
{
	x=_x;
}
void cef_block_blc_pos::setY(double _y)
{
	y=_y;
}
void cef_block_blc_pos::setInitX(double ix)
{
	initialx=ix;
}
void cef_block_blc_pos::setInitY(double iy)
{
	initialy=iy;
}
void cef_block_blc_pos::setMove(bool m)
{
	movable=m;
}
//Getters
double cef_block_blc_pos::getX()
{
	return x;
}
double cef_block_blc_pos::getY()
{
	return y;
}
double cef_block_blc_pos::getInitX()
{
	return initialx;
}
double cef_block_blc_pos::getInitY()
{
	return initialy;
}
bool cef_block_blc_pos::getMove()
{
	return movable;
}
#ifdef _DEBUG	
void cef_block_blc_pos::print()	
{
	cout<<"CEF Block Bottom Left Corner Position\nBEGIN\n";
	cout<<"x: "<<x<<" y: "<<y<<" Initial x: "<<initialx<<" Initial y: "<<initialy<<" Movable: "<<movable<<endl;
	cout<<"END\n";
}
#endif
cef_block_size::cef_block_size()
{
	soft=false;
	area=0;
	shape=NULL;
	aspect_ratio=1;
	
}
cef_block_size::cef_block_size(bool s,vector<pair<double,double>*>* sh,double a,double ar)
{
	soft=s;	
	shape=sh;
	area=a;
	aspect_ratio=ar;
}

cef_block_size::~cef_block_size()
{
	if(shape)
	{
		for(unsigned i=0;i<shape->size();i++)
		{
			delete (*shape)[i];
		}
		delete shape;
	}	
}	
	//Setters
void cef_block_size::setSoft(bool s)
{
	soft=s;
}
void cef_block_size::setShape(vector<pair<double,double>* >* sh)
{
	shape=sh;
}
void cef_block_size::setArea(double a)
{
	area=a;
}
void cef_block_size::setAspectRatio(double ar)
{
	aspect_ratio=ar;
}
//Getters
bool cef_block_size::getSoft()
{
	return soft;
}
vector<pair<double,double>* >* cef_block_size::getShape()
{
	return shape;
}
double cef_block_size::getArea()
{
	return area; 
}
double cef_block_size::getAspectRatio()
{
	return aspect_ratio;
}
#ifdef _DEBUG	
void cef_block_size::print()	
{
	cout<<"CEF Block Size\nBEGIN\n"; 
	cout<<"Soft: "<<soft<<" Area: "<<area<<" Aspect Ratio: "<<aspect_ratio<<endl;
	cout<<"Shape:\n";
	if(shape)
	{
		for(unsigned i=0;i<shape->size();i++) 
		{
			cout<<(*shape)[i]->first<<" "<<(*shape)[i]->second<<"\n";
		}
	}
	else
	{
		cout<<"No Shape Defined!"<<endl;
	}
	cout<<"END\n";
}
#endif
cef_block_orientation::cef_block_orientation()
{
	rotatable=false;
	mirrorable=false;
	rotation=d0;
	initial_rotation=d0;
	mirroringx=false;
	initial_mirroringx=false;
	mirroringy=false;
	initial_mirroringy=false;
}
cef_block_orientation::cef_block_orientation(bool r,bool m,cef_degree_orientation rot,cef_degree_orientation irot,bool mx,bool my,bool imx,bool imy)
{
	rotatable=r;	
	mirrorable=m;
	rotation=rot;
	initial_rotation=irot;
	mirroringx=mx;
	initial_mirroringx=imx;
	mirroringy=my;
	initial_mirroringy=imy;
}
cef_block_orientation::~cef_block_orientation()
{
}
	//Setters
void cef_block_orientation::setRotate(bool r)
{
	rotatable=r;
}
void cef_block_orientation::setMirror(bool m)
{
	mirrorable=m;
}
void cef_block_orientation::setRotation(cef_degree_orientation rot)
{
	rotation=rot;
}
void cef_block_orientation::setInitRotation(cef_degree_orientation irot)
{
	initial_rotation=irot;	
}
void cef_block_orientation::setMirroringX(bool mx)
{
	mirroringx=mx;
}
void cef_block_orientation::setInitMirroringX(bool imx)
{
	initial_mirroringx=imx;
}
void cef_block_orientation::setMirroringY(bool my)
{
	mirroringy=my;
}
void cef_block_orientation::setInitMirroringY(bool imy)
{
	initial_mirroringy=imy;
}
//Getters
bool cef_block_orientation::getRotate()
{
	 return rotatable; 
}

bool cef_block_orientation::getMirror()
{
	return mirrorable;
}
cef_degree_orientation cef_block_orientation::getRotation()
{
	return rotation;
}
cef_degree_orientation cef_block_orientation::getInitRotation()
{
	return initial_rotation;
}
bool cef_block_orientation::getMirroringX()
{
	return mirroringx;
}
bool cef_block_orientation::getInitMirroringX()
{
	return initial_mirroringx;
}
bool cef_block_orientation::getMirroringY()
{
	return mirroringy;
}
bool cef_block_orientation::getInitMirroringY()
{
	return initial_mirroringy;
}
//DEBUG
#ifdef _DEBUG	
void cef_block_orientation::print()	
{
	cout<<"CEF Block Orientation\n BEGIN\n";
	cout<<"Rotatable: "<<rotatable<<" Mirrorable: "<<mirrorable<<" Rotation: "<<rotation<<" Initial Rotation: "<<initial_rotation<<" Mirroring x: "<<mirroringx<<" Mirroring y: "<<mirroringy<<" Init. Mirroring x: "<<initial_mirroringx<<" Init. Mirroring y: "<<initial_mirroringy<<endl;
	cout<<"END\n";
}
#endif
cef_block_architecture::cef_block_architecture()
{
	type="";
	address_ranges=NULL;
	inbuffer=NULL;
	outbuffer=NULL;
	virtual_channels=0;
	vc_arbitration="";
	arbitration_policy="";
	vc_struct="";
}
cef_block_architecture::cef_block_architecture(string t,vector<pair<unsigned long long,unsigned long long>* >* ar, vector<unsigned>* inb,vector<unsigned>* oub,unsigned vcs,string strct,string vca, string arbit):type(t)
{
	address_ranges=ar;	
	inbuffer=inb;
	outbuffer=oub;
	virtual_channels=vcs;
	vc_arbitration=vca;
	arbitration_policy=arbit;
	vc_struct=strct;
}
cef_block_architecture::~cef_block_architecture()
{
	if(address_ranges)
	{
		for(unsigned i=0;i<address_ranges->size();i++)
		{
			delete (*address_ranges)[i];
		}	
		delete address_ranges;
	}
	if(inbuffer)
	{
		delete inbuffer;
	}	
	if(outbuffer)
	{
		delete outbuffer;
	}	
}
	//Setters
void cef_block_architecture::setNIType(string t)
{
	type=t;
}
void cef_block_architecture::setAddrRngs(vector<pair<unsigned long long, unsigned long long>* >* ar)
{
	address_ranges=ar;
}

void cef_block_architecture::setInBuffers(vector<unsigned>* inb)
{
	inbuffer=inb;
}
void cef_block_architecture::setOutBuffers(vector<unsigned>* oub)
{
	outbuffer=oub;
}
void cef_block_architecture::setVCs(unsigned vcs)
{
	virtual_channels=vcs;
}
void cef_block_architecture::setVCArbit(string vca)
{
	vc_arbitration=vca;
}
void cef_block_architecture::setArbit(string a)
{
	arbitration_policy=a;
}
void cef_block_architecture::setVCArbStruct(string s)
{
	vc_struct=s;
}
 
//Getters
string cef_block_architecture::getNIType()
{
	return type;
}
vector<pair<unsigned long long, unsigned long long>* >* cef_block_architecture::getAddrRngs()
{
	return address_ranges;
}
vector<unsigned>* cef_block_architecture::getInBuffers()
{
	return inbuffer;
}
vector<unsigned>* cef_block_architecture::getOutBuffers()
{
	return outbuffer;
}
unsigned cef_block_architecture::getVCs()
{
	return virtual_channels;
}
string cef_block_architecture::getVCArbit()
{
	return vc_arbitration;
}
string cef_block_architecture::getArbit()
{
	return arbitration_policy;
}
string cef_block_architecture::getVCArbStruct()
{
	return vc_struct;
}
#ifdef _DEBUG	
void cef_block_architecture::print()	
{
	cout<<"CEF Block Architecture\nBEGIN\n";
	cout<<"NIType: "<<type<<" VCs: "<<virtual_channels<<" VCArbStruct: "<<vc_struct<<" VC Arbit.: "<<vc_arbitration<<" Arbit.: "<<arbitration_policy<<endl;
	cout<<"Address Ranges: \n";
	if(address_ranges)
	{
		for(unsigned i=0;i<address_ranges->size();i++)
		{
			cout<<"("<<(*address_ranges)[i]->first<<","<<(*address_ranges)[i]->second<<")"<<endl;
		}	
	}
	cout<<"Buffer Size (IN):\n";
	if(inbuffer)
	{
		for(unsigned i=0;i<inbuffer->size();i++)
		{
			cout<<(*inbuffer)[i]<<endl;
		}	
	}	
	cout<<"Buffer Size (OUT):\n";
	if(outbuffer)
	{
		for(unsigned i=0;i<outbuffer->size();i++)
		{
			cout<<(*outbuffer)[i]<<endl;
		}	
	}	
	cout<<"END\n";
}
#endif
cef_block::cef_block()
{
	name="default";
	id=0;
	type=0;
	connections=NULL;
	size=NULL;
	orientation=NULL;
	bottomleftcorner_position=NULL;
	layer=0;
	architecture=NULL;
	ports=NULL;
}
cef_block::cef_block(unsigned i,string n,unsigned t,std::vector<unsigned>* c, vector<cef_port*>* prt,cef_block_size* s, cef_block_orientation* o, cef_block_blc_pos* p,unsigned l, cef_block_architecture* a)
{
	id=i;
	name=n;
	type=t;
	connections=c;
	size=s;
	ports=prt;
	orientation=o;
	bottomleftcorner_position=p;
	layer=l;
	architecture=a;
}
cef_block::~cef_block()
{
	if(connections) delete connections;
	if(size) delete size;
	if(orientation) delete orientation;
	if(bottomleftcorner_position) delete bottomleftcorner_position;
	if(architecture) delete architecture;
}
//Setters
void cef_block::setID(unsigned i)
{
	id=i;
}
void cef_block::setType(unsigned t)
{
	type=t;
}
void cef_block::setName(std::string n)
{
	name=n;
}
void cef_block::setConnections(std::vector<unsigned>* c)
{
	connections=c;
}
void cef_block::setPorts(std::vector<cef_port*>* p)
{
	ports=p;
}
void cef_block::setSize(cef_block_size* s)
{
	size=s;
}
void cef_block::setOrientation(cef_block_orientation* o)
{
	orientation=o;
}
void cef_block::setBotLefCor(cef_block_blc_pos* p)
{
	bottomleftcorner_position=p;
}
void cef_block::setLayer(unsigned l)
{
	layer=l;
}
void cef_block::setArchitecture(cef_block_architecture* a)
{
	architecture=a;
}
//Getters	

unsigned cef_block::getID()
{
	return id;
}
unsigned cef_block::getType()
{
	return type;
}
std::string cef_block::getName()
{
	return name;
}
std::vector<unsigned>* cef_block::getConnections()
{
	return connections;
}
std::vector<cef_port*>* cef_block::getPorts()
{
	return ports;
}
cef_block_size* cef_block::getSize()
{
	return size;
}
cef_block_orientation* cef_block::getOrientation()
{
	return orientation;
}
cef_block_blc_pos* cef_block::getBotLefCor()
{
	return bottomleftcorner_position;
}
unsigned cef_block::getLayer()
{
	return layer;
}
cef_block_architecture* cef_block::getArchitecture()
{
	return architecture;
}
#ifdef _DEBUG	
void cef_block::print()	
{
	cout<<"CEF Block\nBEGIN\n";
	cout<<" ID: "<<id<<" Name: "<<name<<" Type: "<<type<<" Layer: "<<layer<<endl;
	if(connections)
	{
		cout<<"Connections: ";
		for(unsigned i=0;i<connections->size();i++)
		{
			cout<<(*connections)[i]<<" ";
		}
		cout<<endl;
	}	
	if(size) size->print();
	if(bottomleftcorner_position) bottomleftcorner_position->print();
	if(orientation) orientation->print();
	if(ports)
	{
		cout<<"Ports:\n";
		for(unsigned j=0;j<ports->size();j++)
		{
			(*ports)[j]->print();
		}
		cout<<"End of ports"<<endl;
	}
	cout<<"END\n";	
}
#endif
